package shoooter;


import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import java.awt.image.*;
import shoooter.entity.bonus.BombBonus;
import shoooter.entity.bonus.Bonus;
import shoooter.entity.bonus.FastShootBonus;
import shoooter.entity.bonus.HealBonus;
import shoooter.entity.nonimage.*;
import shoooter.entity.nonimage.enemy.EasyEnemy;
import shoooter.entity.nonimage.enemy.Enemy;
import shoooter.geometry.Vec2;
import shoooter.save.HighscoreManager;


/* faccio test */


public class Shoooter extends JFrame implements Runnable {
    

    BufferedImage bufImage = null;

    /* Elementi Grafici */
    Panel pan = null;
    JLabel lab = null;
    JLabel labStatus = null;
    JMenuBar menuBar;

    /* Struttura del giocatore */
    SimplePlayer player = null;

    /* Vettori del movimento del cerchio */
    Vec2 vPos = null;
    Vec2 vSpe = null;
    Vec2 vAcc = null;

    /* Variabili */
    final int FPS = 50;
    final int RATE = (int) 1000 / FPS;
    final int FIX_MOV = 3;

    /* Lato fisso del pannello di gioco (che è un quadrato) */
    final int FIXED = 400;

    /* Altezza e Larghezza della finestra (non del pannello di gioco) */
    final int WINDOW_HEIGHT = 454;
    final int WINDOW_WIDTH = 400;

    /* limite per passaggio di livello e spawn del bonus */
    final int level_limit = 25;
    final int bonus_limit = FPS * 4;    // ogni 20 secondi
    
    /* Coordinate del mouse */
    int mouseX = 0, mouseY = 0;

    /* Indice per lo scorrimento dell'array 
       dei proiettili e dei nemici */
    int projs = 0, enems = 0;

    int passedTime = 0;

    int MAX_SPEED = 5;
    int MAX_ENEMS = 5;

    int count = 0;
    int life_count = 0;
    int bonus_count = 0;
    int spawn_count = 40;

    int explode_count = 0;
    int explode_limit = FPS * 10;  // ogni 10 secondi

    int this_bonus = 0;
    
    int enemies_killed = 0;

    boolean got_shield = false;

    /* GameState: stato delle variabili modificabili dai bonus */
    GameState gState = null;

    boolean shoot = false;
    boolean paused = false;

    /* Array dei proiettili */
    Projectile[] points = null;
    /* Array dei nemici */
    EasyEnemy[] enemy = null;
    
    Bonus[] bonus = null;
    Bonus[] activeBonus = null;

    /* Titolo in alto della finestra, vicino all'icona del programma */
    javax.swing.Timer gameTime = new javax.swing.Timer(1000, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            setTitle(" Time Played: " + (int)(passedTime/60) + ":" + ( (passedTime%60) < 10 ? "0" : "") + passedTime%60 );
            passedTime++;
        }
    });

    /* Array per tenere le pressioni nelle varie direzioni */
    boolean[] dir = new boolean[4];

    /* Costanti delle direzioni */
    public static final int N = 1, E = 2, S = 3, O = 4;

    /* Costanti per il tipo di bonus */
    public static final int FAST = 0, SHIELD = 1, BOMB = 2;

    /* Trigger per i bonus */
    final static int ON = 0, OFF = 1;

    /* Thread del programma */
    Thread loop;

    Graphics2D g2d = null;

    KeyListener keyL = null;
    KeyListener keyL2 = null;
    MouseListener mouseL = null;
    MouseMotionListener mouseML = null;
    WindowFocusListener wFL = null;

    /* Seed fisso: per prove */
    Random rand = new Random(32487679);
    
    Image background = new ImageIcon(getClass().getResource("background.png")).getImage();
    
    int startBackground = 0 , endBackground = -300; 

    /* The game start here! (ma in che lingua scriviamo i commenti?) */
    public Shoooter()
    {

//        bufImage = new BufferedImage(400,400, BufferedImage.TYPE_INT_RGB);

        /* Inizializzazione elementi interfaccia */
        pan = new Panel();
        lab = new JLabel();
        labStatus = new JLabel();

        init();

        /* Listener per la chiusura della finestra */
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent w) {
                closeGame();
            }
        });

        addWindowListener(new WindowAdapter() {
            public void windowResize(WindowEvent w) {
                lab.setText("Resized..");
            }
        });


        keyL = new KeyAdapter() { // http://download.oracle.com/javase/7/docs/api/java/awt/event/KeyAdapter.html

            @Override
            public void keyPressed(KeyEvent e) {
                int keyV = e.getKeyCode();

                switch(keyV) {
                    case KeyEvent.VK_P: // Pulsante P
                        if(paused) {
                            labStatus.setText(null);
                            start();
                            paused = false;
                        }
                        else {
                            stop();
                            labStatus.setText("Game paused. Press P to continue.");
                            paused = true;
                        }
                        break;
                    case KeyEvent.VK_UP:
                    case KeyEvent.VK_W:
                        dir[0] = true;
                        dir[2] = false;
                        break;
                    case KeyEvent.VK_RIGHT:
                    case KeyEvent.VK_D:
                        dir[1] = true;
                        dir[3] = false;
                        break;
                    case KeyEvent.VK_DOWN:
                    case KeyEvent.VK_S:
                        dir[2] = true;
                        dir[0] = false;
                        break;
                    case KeyEvent.VK_LEFT:
                    case KeyEvent.VK_A:
                        dir[3] = true;
                        dir[1] = false;
                        break;
                    case KeyEvent.VK_F:
                        labStatus.setText("BOMB DROPPED!");
                        player.useSperimentalBomb();
                        break;
                    case KeyEvent.VK_E:
                        explode();
                        break;
                    default:
                        break;
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
                int keyV = e.getKeyCode();

                switch(keyV) {
                    case KeyEvent.VK_UP:
                    case KeyEvent.VK_W:
                        dir[0] = false;
                        break;
                    case KeyEvent.VK_RIGHT:
                    case KeyEvent.VK_D:
                        dir[1] = false;
                        break;
                    case KeyEvent.VK_DOWN:
                    case KeyEvent.VK_S:
                        dir[2] = false;
                        break;
                    case KeyEvent.VK_LEFT:
                    case KeyEvent.VK_A:
                        dir[3] = false;
                    default:
                        break;
                }
            }
        };

        
        mouseL = new MouseListener() { // http://download.oracle.com/javase/1.4.2/docs/api/java/awt/event/MouseListener.html

            @Override
            public void mouseClicked(MouseEvent e) {
                
            }


            @Override
            public void mousePressed(MouseEvent e) {
                mouseX = e.getX();
                mouseY = e.getY();
                shoot = true;
                
                if(loop == null && !player.isAlive())
                {
                    init();
                    start();
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                mouseX = 0;
                mouseY = 0;
                shoot = false;
                life_count = 0;
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                if(player.isAlive() && !paused)
                    start();
            }

            @Override
            public void mouseExited(MouseEvent e) {
                if(!paused)
                    stop();
            }
        };

        mouseML = new MouseMotionListener() {

            @Override
            public void mouseDragged(MouseEvent e) {
                mouseX = e.getX();
                mouseY = e.getY();
                shoot = true;
            }

            @Override
            public void mouseMoved(MouseEvent e) {
                mouseX = e.getX();
                mouseY = e.getY();
            }
        };

        wFL = new WindowFocusListener() {

            @Override
            public void windowGainedFocus(WindowEvent e) {
                if(player.isAlive() && !paused) {
                    start();
                    dir[0] = dir[1] = dir[2] = dir[3] = false;
                }
            }

            @Override
            public void windowLostFocus(WindowEvent e) {
                stop();
            }
        };

        addWindowFocusListener(wFL);

        addKeyListener(keyL);
//        addKeyListener(keyL2);
        pan.addKeyListener(keyL);
//        pan.addKeyListener(keyL2);
        pan.addMouseListener(mouseL);
        pan.addMouseMotionListener(mouseML);

        pan.setSize(FIXED, FIXED);

        Container cp = getContentPane();
        
        
        menuBar = new JMenuBar();
        JMenu mFile = new JMenu("File");
        JMenuItem recordItem = new JMenuItem("Record");
        recordItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(null, "Da Implementare");
            }
        });
        JMenuItem sizeItem = new JMenuItem("World Size");
        sizeItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(null, "Da Implementare");
            }
        });
        JMenuItem highsItem = new JMenuItem("Highscore");
        highsItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(null, HighscoreManager.getHighscore());
            }
        });
        JMenuItem exitItem = new JMenuItem("Exit");
        exitItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                closeGame();
            }
        });
        
        JMenu info = new JMenu("Help");
        JMenuItem aboutItem = new JMenuItem("About");
        aboutItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(null, "Created by:\nSimone Aonzo\nVegna Alessandro");
            }
        });
        JMenuItem versionItem = new JMenuItem("About");
        versionItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(null, "Da Implementare");
            }
        });
        
        
        info.add(aboutItem);
        info.add(versionItem);
        mFile.add(recordItem);
        mFile.add(sizeItem);
        mFile.add(highsItem);
        mFile.add(exitItem);
        
        menuBar.add(mFile);
        menuBar.add(info);

        cp.setLayout(new BorderLayout());
        cp.add(lab, BorderLayout.NORTH);
        cp.add(menuBar, BorderLayout.NORTH);
        

        cp.add(labStatus, BorderLayout.SOUTH);
        cp.add(pan, BorderLayout.CENTER);

        setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
        setResizable(false);
        // center the frame
        this.setLocationRelativeTo(null);
        setVisible(true);

        start();
    }

    
    public boolean canMove()
    {

        double x = player.getX();
        double y = player.getY();
        int rad = player.rad;

        if(x-rad <= 0.0 || y-rad <= 0.0 || x+rad >= 400.0 || y+rad >= 400.0 )
            return false;

        return true;
    }

    
    private void closeGame()
    {
        System.exit(0);
    }

    
    private void explode()
    {

        double full_angle = 2 * Math.PI;
        double rad = 0.0;
        double step = full_angle / gState.POINTS;

        int i;

        if(explode_count < explode_limit)
            return;

        explode_count = 0;
        life_count = 0;
        gState.shoot_timer = 0;

        Vec2 myV;
        Vec2 myVp;

        for(i = projs = 0; i < gState.POINTS; rad -= step,  i++) {

            myV = new Vec2();
            myVp = new Vec2(player.getX(), player.getY());
            
            myV.setX(5*Math.cos(rad));
            myV.setY(5*Math.sin(rad));

            myVp.incrX(player.rad*Math.cos(rad));
            myVp.incrY(player.rad*Math.sin(rad));

            points[projs] = new Projectile(myVp, myV);
            projs = (projs >= gState.POINTS-1) ? 0 : projs+1;
        }
    }

    public void bounce()
    {

        boolean modified = false;

        double offset, newValue;

        double x = player.getX();
        double y = player.getY();

        int rad = player.rad;

        double xSp = player.getvSpe().getX();
        double ySp = player.getvSpe().getY();
        
        if((x-rad) < 0.0) {
            player.setX(rad);
            modified = true;
         }
         else if ((x+rad) > FIXED-1) {
            player.setX(FIXED-1 - rad);
            modified = true;
         }

         if ((y-rad) < 0.0) {
            player.setY(rad);
            modified = true;
         }
         else if ((y+rad) > FIXED-1) {
            player.setY(FIXED-1 - rad);
            modified = true;
         }
    }

    
    @Override
    public void paint(Graphics g)
    {
        Font f;
        int i = 0;

        Graphics gg = (Graphics2D) pan.getGraphics();
        g2d = (Graphics2D) bufImage.getGraphics();

        super.paint(g);

        /* Controllo se la partita è terminata */
        if(loop == null && !player.isAlive())  {
            
            f = g2d.getFont();

            //g2d.setColor(Color.white);
            g2d.drawImage(background, 0, 0,FIXED-1,FIXED-1,null);
            //g2d.fillRect(0,0,FIXED,FIXED);
            g2d.setColor(Color.white);
            g2d.drawRect(0, 0, FIXED-1, FIXED-1);

            g2d.setFont(new Font(f.getName(), Font.BOLD, 40));

            if ( HighscoreManager.manageHighscore(gState.score)  ) {
                g2d.setColor(Color.yellow);
                g2d.drawString("HIIIIIGHSCOOORE!!!!", 1, 300);
            }
            
            g2d.setColor(Color.red);
            g2d.drawString("SCORE FINALE:", 50, 100);

            g2d.setColor(Color.white);
            g2d.drawString(String.valueOf(gState.score), 180, 140);

            g2d.setFont(f);
            g2d.drawString("Clicca sullo schermo per ricominciare!", 80, 200);
            
            /* Gestione highscore */
            
            

            lab.setText("Livello Raggiunto: " + gState.level);

            gg.drawImage(bufImage, 0, 0, null);
            

            return;
        }

        // draw background
        //g2d.setColor(Color.white);
        
        g2d.drawImage(background, startBackground, 0,FIXED-1,FIXED-1,null);
        g2d.drawImage(background, endBackground, 0,FIXED-1,FIXED-1,null);
        
        //g2d.fillRect(0, 0, FIXED-1, FIXED-1);
        
        //set animated back
        if(startBackground < 300 ) 
            startBackground++;
        else startBackground = 0;
        
        if(endBackground < 0 ) 
            endBackground++;
        else endBackground = -300;
        

        g2d.setColor(Color.white);
        g2d.drawRect(0, 0, FIXED-1, FIXED-1);

        g2d.drawString("Score: " + gState.score, 50, 40);
        g2d.drawString("Enemies: " + this.MAX_ENEMS, 50, 55);
        g2d.drawString("Bombs: " + player.bombs, 50, 70);

        // Disegna la barra dell'explode
        if(explode_count < explode_limit)
            g2d.drawString("Explode...", 310, 375);
        else
            g2d.drawString("READY! (E)", 310, 375);

        g2d.setColor(Color.blue);
        g2d.fillRect(300, 380, ((explode_count >= explode_limit) ? explode_limit : explode_count) * 80 / explode_limit, 15);
        g2d.setColor(Color.white);
        g2d.drawRect(300, 380, 80, 15);

        // Disegna l'evenuale barra del cosoFire

        if(gState.shoot_timer_limit == 1 && (gState.level % 5) != 0) {
            g2d.drawString("F.FIRE!", 251, 375);
            
            g2d.setColor(Color.green);
            g2d.fillRect(250, 380, 40-(activeBonus[FAST].elapsed_time * 40 / activeBonus[FAST].elapsed_limit), 15);
            g2d.setColor(Color.white);
            g2d.drawRect(250, 380, 40, 15);
        }


        for(Bonus b: bonus)
            if(b!=null && !b.taken)
                b.draw(g2d);

        for(Bomb b: gState.bomb)
            if( b!=null && b.elapse() )
                b.draw(g2d);

        for(Projectile p: points)
            if(p!=null && p.isAlive())
                p.draw(g2d);

        for(EasyEnemy e: enemy)
            if(e!=null && e.isAlive())
                e.draw(g2d);

        for(i = 0; i < gState.p.bombs ;i++) {
            g2d.setColor(Color.yellow);
            g2d.fillOval(10+i*15, 380, 10, 10);
            g2d.setColor(Color.white);
            g2d.drawOval(10+i*15, 380, 10, 10);
        }

        //draw life bar
        GradientPaint gradient = new GradientPaint(500,200,Color.red,600,200 ,Color.green,true);
        g2d.setPaint(gradient);
        
        g2d.fillRect(300, 10, player.hp >= 100 ? 70 : player.hp * 70 / 100, 15);
        g2d.setColor(Color.white);
        g2d.drawRect(300, 10, 70, 15);
        g2d.drawString("HP", 280, 22);
        g2d.drawString(String.valueOf(player.hp), player.hp >= 100 ? 323 : 327, 22);

        
        player.draw(g2d,(mouseX == 0 ? 1 : mouseX),(mouseY == 0 ? 1 : mouseY));
        gg.drawImage(bufImage, 0, 0, null);
        
        
    }
        

    public void gameUpdate()
    {

/*
        if( dir[0] && player.getvSpe().getY() > -MAX_SPEED  )
            player.getvSpe().incrY(-FIX_MOV);

        if( dir[1] && player.getvSpe().getX() < MAX_SPEED )
            player.getvSpe().incrX(FIX_MOV);

        if( dir[2] && player.getvSpe().getY() < MAX_SPEED)
            player.getvSpe().incrY(FIX_MOV);

        if( dir[3] && player.getvSpe().getX() > -MAX_SPEED )
            player.getvSpe().incrX(-FIX_MOV);
*/
        if( dir[0] )
            player.getvSpe().setY(-MAX_SPEED);

        if( dir[1] )
            player.getvSpe().setX(MAX_SPEED);

        if( dir[2] )
            player.getvSpe().setY(MAX_SPEED);

        if( dir[3] )
            player.getvSpe().setX(-MAX_SPEED);

        if( !(dir[0] || dir[2]) )
            player.getvSpe().setY(0);

        if( !(dir[1] || dir[3]) )
            player.getvSpe().setX(0);

        player.setX(player.getX() + player.getvSpe().getX());
        player.setY(player.getY() + player.getvSpe().getY());
        
        bounce();

        adjustPos();

        moveProj();
        repaint();

        gState.shoot_timer++;
        count++;
        bonus_count++;
        explode_count++;

        if(shoot && gState.shoot_timer >= gState.shoot_timer_limit) {

            life_count = 0;
            gState.shoot_timer = 0;

            Vec2 myV = new Vec2();
            Vec2 myVp = new Vec2(player.getX(), player.getY());
            
            double rad = Math.atan2(mouseY - player.getY(), mouseX - player.getX());

            /* Se è attivo il turbo-fire, spara a spread */

            //labStatus.setText("rads: " + rad);
            if(gState.shoot_timer_limit == 1){
                switch(rand.nextInt(7)) {
                    case 0:
                        rad -= 0.15;
                        break;
                    case 1:
                        rad -= 0.10;
                        break;
                    case 2:
                        rad -= 0.05;
                        break;
                    case 3:
                        break;
                    case 4:
                        rad += 0.05;
                        break;
                    case 5:
                        rad += 0.10;
                        break;
                    case 6:
                        rad += 0.15;
                        break;
                }
            }

            myV.setX(5*Math.cos(rad));
            myV.setY(5*Math.sin(rad));

            myVp.incrX(player.rad*Math.cos(rad));
            myVp.incrY(player.rad*Math.sin(rad));

            points[projs] = new Projectile(myVp, myV);
            projs = (projs >= gState.POINTS-1) ? 0 : projs+1;
        }
        else {
            life_count++;
            if(life_count == 10) {
                player.regenerate();
                life_count = 0;
            }
        }

        
        if( count >= spawn_count ) {
            enemy[enems] = new EasyEnemy(rand.nextInt(360) + 20, rand.nextInt(360) + 20);
            enems = (enems >= MAX_ENEMS-1) ? 0 : enems+1;
            count = 0;
        }

        
        if( bonus_count == bonus_limit ) {

//            switch( rand.nextInt(3) ) {
            switch( rand.nextInt(3) ) {
                case 0:
                    bonus[this_bonus] = new FastShootBonus(gState);
                    break;
                case 1:
                    bonus[this_bonus] = new HealBonus(gState);
                    break;
                case 2:
                    bonus[this_bonus] = new BombBonus(gState);
                    break;
            }
            this_bonus = (this_bonus+1)%2;
            bonus_count = 0;
        }

        for(Bonus b: bonus) {
            if(b!=null && !b.taken)
                if(Vec2.distance(b.vPos, player.vPos) < ((b.h+b.w)/2 + player.rad)) {
                    activeBonus[b.getType()] = b;
                    bonus[this_bonus] = null;
                    b.take();
                }
            }

        for(Bonus b: activeBonus)
            if(b!=null)
                if( !b.elapse() )
                    b = null;


        for(Bomb b: gState.bomb)
            if(b!=null) {
                if( b.elapse() && b.exploding ) {
                    b.hit(enemy);
                    b.hit1(player);
//                    for(EasyEnemy e: enemy)
//                        if(e!= null && e.die()) {
//                                gState.score+=e.getScore();
//                                enemies_killed++;
//                                if((enemies_killed%level_limit)==0)
//                                    nextLevel();
//
//                                //e.setAlive(false);
//                                e = null;
//                        }
                }
                else
                    b = null;

            }

        if(player.die()) {
            stop();
            labStatus.setText("Gioco Finito.");
            repaint();
        }

/*
        for(Bomb b: gState.bomb)
            if(b!=null) {
                if( b.elapse() ) {
                    if( b.exploding )
                        b.hit(enemy);
                }
                else
                    b = null;

            }

        for(EasyEnemy e: enemy)
            if(e!=null && !e.isAlive()) {
                gState.score+=e.getScore();
                enemies_killed++;
                if((enemies_killed%level_limit)==0)
                    nextLevel();

                //e.setAlive(false);
                //e.setAlive(false);
            }
*/
        
        for(EasyEnemy e: enemy)
            if(e!=null) {
                e.moveToward(player);
                for(Projectile p: points) {
                    if(p!=null && p.isAlive())
                        if(/*e != null &&*/ e.isAlive() && e.hitten(p)) {
                            p.setAlive(false);
                            e.hit(player.power);
                            if(e.die()) {
                                gState.score+=e.getScore();
                                enemies_killed++;
                                if((enemies_killed%level_limit)==0)
                                    nextLevel();
                                
                                //e.setAlive(false);
                                //e = null;
                            }
                        }
                }
                if(e!=null && e.isAlive())
                    if( Vec2.distance(player.getvPos(), e.getvPos()) < (player.rad + e.radi) ) {
                        
                        /** Enemy hits Player */
                        player.hit(10); 
                        
                        e.hp = 0;
                        gState.score--;
                        if(player.die()) {
                            stop();
                            labStatus.setText("Gioco Finito.");
                            repaint();
                        }
                    }
            }
  

    }

    public void myPaint(Graphics2D g2d) {
        
    }

    public void moveProj()
    {

        for(Projectile p: points)
            if(p!=null)
                p.move();
               
    }

    public void nextLevel()
    {

        gState.level++;

        if( gState.shoot_timer_limit == 1 && activeBonus[FAST] != null && !activeBonus[FAST].isActive())
            gState.turboFire(OFF);

        if((gState.level % 2) == 0 ) {

            if(gState.level < 10) {
                Enemy.SPEED++;
                this.MAX_SPEED++;
            }

            /* Level up difficolta' */
            if(gState.level == 10)
                Enemy.SPEED++;

            /* Level up difficolta' */
            if(gState.level == 20)
                Enemy.SPEED++;

            if( (gState.level % 4) == 0) {
                
                if(this.MAX_ENEMS < 10)
                    this.MAX_ENEMS++;

                if(this.spawn_count > 15)
                    this.spawn_count -= 5;
                else if(this.spawn_count <= 15 && this.spawn_count > 10)
                    this.spawn_count -= 1;

                /* hp BONUS */
                if((gState.level % 8) == 0) {
                    player.hp = (player.hp > 120) ? 150 : player.hp + 30;

                    if((gState.level % 5) == 0) {
                        gState.turboFire(ON);
                        labStatus.setText("Level: " + gState.level + " - HP BONUS! - TurboFire ON!");
                    }
                    else
                        labStatus.setText("Level: " + gState.level + " - HP BONUS!");
                    
                    return;
                }
            }
        }

        /* se il livello è multiplo di 5,
           attiva il turbo-fire */
        if((gState.level % 5) == 0) {
            gState.turboFire(ON);
            labStatus.setText("Level: " + gState.level + " - TurboFire ON!");
            return;
        }
        
        labStatus.setText("Level: " + gState.level);
    }

    public final void init()
    {

        mouseX = 0;
        mouseY = 0;

        projs = 0;
        enems = 0;

        passedTime = 0;

        MAX_SPEED = 5;
        MAX_ENEMS = 5;

        count = 0;
        life_count = 0;
        bonus_count = 0;
        spawn_count = 40;

        explode_count = 0;

        this_bonus = 0;
        enemies_killed = 0;

        got_shield = false;
        shoot = false;
        paused = false;

        bufImage = new BufferedImage(FIXED, FIXED, BufferedImage.TYPE_INT_RGB);

        /* Vettori posizione, velocita e accelerazione */
        vPos = new Vec2(200, 200);
        vSpe = new Vec2(0, 0);      // non zero solo per prova debug
        vAcc = new Vec2(0, 0);

        player = new SimplePlayer(vPos, vSpe, vAcc);

        dir[0] = dir[1] = dir[2] = dir[3] = false;

        points = new Projectile[100];
        enemy = new EasyEnemy[10];
        bonus = new Bonus[2];
        activeBonus = new Bonus[3];

        Enemy.SPEED = 3;

        gState = new GameState();
        gState.setPlayer(player);
        gState.enemies = enemy;

        player.g = gState;

        labStatus.setText("Level: " + gState.level);
        lab.setText(" ");

        /* Titolo applicazione*/
        this.setTitle("Shoooter v"+Shoooter.version());
        

    }

    /* Thread Events */
    @Override
    public void run()
    {

        Thread t = Thread.currentThread();

//        lab.setText("GET READY TO PLAY!");

        try {
            if(t==loop) {
                lab.setText("GET READY TO PLAY..2!");
                Thread.sleep(1000);
            }
            if(t==loop) {
                lab.setText("GET READY TO PLAY..1!");
                Thread.sleep(1000);
            }
            if(t==loop)
                lab.setText("GAME STARTED!");
            
        } catch(Exception e) {}

        gameTime.start();

        while(t==loop) {
            //if(!paused) {
                try {
                    Thread.sleep(RATE);
                } catch (Exception e) { }

                gameUpdate();
            //}
        }
    }


    public final void start()
    {
        loop = new Thread(this);
        loop.start();
    }

    public void stop()
    {
        loop = null;
        gameTime.stop();
        if(player.isAlive())
            lab.setText("GAME PAUSED!");
    }
    
    private void adjustPos()
    {
        double x = player.getX();
        double y = player.getY();

        if(x == Double.NaN )
            player.setX(0.0);

        if(y == Double.NaN )
            player.setY(0.0);
    }
    
    static String version()
    { 
        return "0.1";
    }


    public static void main(String[] args)
    {
        Shoooter shoooter = new Shoooter();
    }

}
